package com.leadingsoft.pwxk.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.leadingsoft.common.exception.DataValidateException;
import com.leadingsoft.pwxk.common.PagingPlugin;
import com.leadingsoft.pwxk.dto.AuditBaseInfoDto;
import com.leadingsoft.pwxk.dto.AuditCertDto;
import com.leadingsoft.pwxk.dto.BaseInfoDto;
import com.leadingsoft.pwxk.dto.CategoryDto;
import com.leadingsoft.pwxk.dto.LicenseInfoDto;
import com.leadingsoft.pwxk.dto.PagingTableDto;
import com.leadingsoft.pwxk.dto.PwxkzBasicDto;
import com.leadingsoft.pwxk.dto.SearchDto;
import com.leadingsoft.pwxk.enums.PollutantEnum;
import com.leadingsoft.pwxk.enums.WPType;
import com.leadingsoft.pwxk.model.AuditBaseInfo;
import com.leadingsoft.pwxk.model.LicenseInfo;
import com.leadingsoft.pwxk.model.QAirQcPollution;
import com.leadingsoft.pwxk.model.QBaseInfo;
import com.leadingsoft.pwxk.model.QDrainInfoWaterApplyCountTwo;
import com.leadingsoft.pwxk.model.QLatestData;
import com.leadingsoft.pwxk.model.QLicenseInfo;
import com.leadingsoft.pwxk.model.QPwBaseInfo;
import com.leadingsoft.pwxk.model.QSummary;
import com.leadingsoft.pwxk.model.RiverBasinRegionRelation;
import com.leadingsoft.pwxk.repository.BaseInfoRepository;
import com.leadingsoft.pwxk.repository.LicenseInfoRepository;
import com.leadingsoft.pwxk.repository.RiverBasinRegionRelationRepository;
import com.leadingsoft.pwxk.service.AuditBaseInfoService;
import com.leadingsoft.pwxk.service.AuditCertService;
import com.leadingsoft.pwxk.service.BaseInfoService;
import com.leadingsoft.pwxk.service.CategoryService;
import com.leadingsoft.pwxk.service.LicenseInfoService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.jpa.impl.JPAQuery;

/**
 * 
 * @author ysh
 * @desc 获取发证后-许可证发证信息-服务类
 */
@Service
public class LicenseInfoServiceImpl implements LicenseInfoService {

	@Autowired
	LicenseInfoRepository licenseInfoRepository;

	@Autowired
	BaseInfoRepository baseInfoRepository;

	@Autowired
	AuditBaseInfoService auditBaseInfoService;

	@Autowired
	AuditCertService auditCertService;

	@Autowired
	CategoryService categoryService;

	@Autowired
	BaseInfoService baseInfoService;

	private final QPwBaseInfo pwBaseInfo = QPwBaseInfo.pwBaseInfo;

	private final QBaseInfo baseInfo = QBaseInfo.baseInfo;

	private final QLicenseInfo licenseInfo = QLicenseInfo.licenseInfo;

	private final QAirQcPollution qAirQcPollution = QAirQcPollution.airQcPollution;

	QSummary qSummary = QSummary.summary;

	QLatestData qLatestData = QLatestData.latestData;

	QDrainInfoWaterApplyCountTwo drainInfoWaterApplyCountTwo = QDrainInfoWaterApplyCountTwo.drainInfoWaterApplyCountTwo;

	@Autowired
	private EntityManager em;

	@Autowired
	RiverBasinRegionRelationRepository riverBasinRegionRelationRepository;

	@Override
	public Page<LicenseInfo> getList(Pageable pageable, SearchDto searchDto) {
		BooleanBuilder builder = new BooleanBuilder();
		return licenseInfoRepository.findAll(builder.getValue(), pageable);
	}

	@Override
	public PagingTableDto<LicenseInfoDto> getList(SearchDto searchDto) {

		if (null == searchDto.getWrwType()) {
			return notNeedWrwInfo(searchDto);
		} else {
			return needWrwInfo(searchDto);
		}
	}

	@SuppressWarnings({ "rawtypes" })
	private PagingTableDto<LicenseInfoDto> notNeedWrwInfo(SearchDto searchDto) {
		List<LicenseInfoDto> list = new ArrayList<LicenseInfoDto>();
		JPAQuery<Tuple> query = new JPAQuery<>(em);
		query.select(pwBaseInfo.devcompany, pwBaseInfo.hyname, baseInfo.name_region, baseInfo.name_regiondetail,
				licenseInfo.xkzNum, licenseInfo.times, licenseInfo.fztime, licenseInfo.dataid, pwBaseInfo.enterid);
		query.from(qLatestData).leftJoin(licenseInfo).on(qLatestData.dataid.eq(licenseInfo.dataid)).leftJoin(pwBaseInfo)
				.on(licenseInfo.dataid.eq(pwBaseInfo.dataid)).leftJoin(baseInfo)
				.on(pwBaseInfo.enterid.eq(baseInfo.enterid));
		bulidFilterBox(searchDto, query);
		OrderSpecifier[] orderSpecifier = { licenseInfo.fztime.desc() };
		query.orderBy(orderSpecifier);
		List<RiverBasinRegionRelation> rb = new ArrayList<RiverBasinRegionRelation>();
		if (StringUtils.isNotBlank(searchDto.getRiverBasinName())) {
			rb = riverBasinRegionRelationRepository.findByRiverBasinName(searchDto.getRiverBasinName());
		}
		List<Tuple> fetch = query.distinct().fetch();
		Map<String, Tuple> distinctMap = new LinkedHashMap<String, Tuple>();
		fetch.forEach(t -> {
			if (null == distinctMap.get(t.get(pwBaseInfo.enterid))) {
				distinctMap.put(t.get(pwBaseInfo.enterid), t);
			}
		});
		for (Tuple data : distinctMap.values()) {
			LicenseInfoDto licenseInfoDto = new LicenseInfoDto();
			licenseInfoDto.setDevcompany(data.get(pwBaseInfo.devcompany));
			licenseInfoDto.setFztime(data.get(licenseInfo.fztime));
			licenseInfoDto.setHyname(data.get(pwBaseInfo.hyname));
			licenseInfoDto.setNameRegion(data.get(baseInfo.name_region));
			licenseInfoDto.setNameRegionDetail(data.get(baseInfo.name_regiondetail));
			licenseInfoDto.setXkzNum(data.get(licenseInfo.xkzNum));
			licenseInfoDto.setTimes(data.get(licenseInfo.times));
			licenseInfoDto.setDataid(data.get(licenseInfo.dataid));
			if (!rb.isEmpty()) {
				for (RiverBasinRegionRelation r : rb) {
					if (r.getRegionName().indexOf(licenseInfoDto.getNameRegion()) != -1
							&& r.getRegionDetailName().indexOf(licenseInfoDto.getNameRegionDetail()) != -1) {
						list.add(licenseInfoDto);
					}
				}
			} else {
				list.add(licenseInfoDto);
			}

		}
		return PagingPlugin.getLocalPagingInfo(list, searchDto);
	}

	@SuppressWarnings({ "rawtypes" })
	private PagingTableDto<LicenseInfoDto> needWrwInfo(SearchDto searchDto) {
		JPAQuery<Tuple> query = new JPAQuery<>(em);
		List<LicenseInfoDto> list = new ArrayList<LicenseInfoDto>();
		if (StringUtils.isBlank(searchDto.getYear())) {
			throw new DataValidateException("获取污染物信息时，年度参数不能为空");
		}
		query.select(licenseInfo.dataid, pwBaseInfo.devcompany, pwBaseInfo.hyname, baseInfo.name_region,
				baseInfo.name_regiondetail, licenseInfo.xkzNum, licenseInfo.times,
				licenseInfo.fztime.substring(0, licenseInfo.fztime.indexOf("-")), licenseInfo.fztime,
				pwBaseInfo.enterid);
		query.from(qLatestData).leftJoin(licenseInfo).on(qLatestData.dataid.eq(licenseInfo.dataid)).leftJoin(pwBaseInfo)
				.on(licenseInfo.dataid.eq(pwBaseInfo.dataid)).leftJoin(baseInfo)
				.on(pwBaseInfo.enterid.eq(baseInfo.enterid));
		bulidFilterBox(searchDto, query);
		OrderSpecifier[] orderSpecifier = { licenseInfo.fztime.desc() };
		query.orderBy(orderSpecifier);
		List<RiverBasinRegionRelation> rb = new ArrayList<RiverBasinRegionRelation>();
		if (StringUtils.isNotBlank(searchDto.getRiverBasinName())) {
			rb = riverBasinRegionRelationRepository.findByRiverBasinName(searchDto.getRiverBasinName());
		}
		List<Tuple> tempfetch = null;
		JPAQuery<Tuple> tempQuery = new JPAQuery<>(em);
		if (searchDto.getWrwType().equals(WPType.WATER)) {
			tempQuery.select(drainInfoWaterApplyCountTwo.sqoneyear, drainInfoWaterApplyCountTwo.sqtwoyear,
					drainInfoWaterApplyCountTwo.sqthreeyear, drainInfoWaterApplyCountTwo.sqfouryear,
					drainInfoWaterApplyCountTwo.sqfiveyear, drainInfoWaterApplyCountTwo.waterwrwcode,
					drainInfoWaterApplyCountTwo.dataid);
			tempQuery.from(drainInfoWaterApplyCountTwo);
			tempfetch = tempQuery.distinct().fetch();
		}
		if (searchDto.getWrwType().equals(WPType.GAS)) {
			tempQuery.select(qAirQcPollution.qconeyear, qAirQcPollution.qctwoyear, qAirQcPollution.qcthreeyear,
					qAirQcPollution.qcfouryear, qAirQcPollution.qcfiveyear, qAirQcPollution.wrwid,
					qAirQcPollution.dataid);
			tempQuery.from(qAirQcPollution);
			tempfetch = tempQuery.distinct().fetch();
		}
		List<Tuple> fetch = query.distinct().fetch();
		Map<String, Tuple> distinctMap = new HashMap<String, Tuple>();
		fetch.forEach(t -> {
			distinctMap.put(t.get(pwBaseInfo.enterid), t);
		});
		for (Tuple t : distinctMap.values()) {
			LicenseInfoDto dto = new LicenseInfoDto();
			dto.setDataid(t.get(licenseInfo.dataid));
			dto.setNameRegion(t.get(baseInfo.name_region));
			dto.setNameRegionDetail(t.get(baseInfo.name_regiondetail));
			dto.setXkzNum(t.get(licenseInfo.xkzNum));
			dto.setDevcompany(t.get(pwBaseInfo.devcompany));
			dto.setHyname(t.get(pwBaseInfo.hyname));
			String dataId = t.get(licenseInfo.dataid);
			if (!rb.isEmpty()) {
				for (RiverBasinRegionRelation r : rb) {
					if (r.getRegionName().indexOf(dto.getNameRegion()) != -1
							&& r.getRegionDetailName().indexOf(dto.getNameRegionDetail()) != -1) {
						if (searchDto.getWrwType().equals(WPType.WATER)) {
							getWaterWrwInfo(searchDto, dto, dataId, t.get(licenseInfo.fztime), tempfetch);
						}
						if (searchDto.getWrwType().equals(WPType.GAS)) {
							getAirWrwInfo(searchDto, dto, dataId, t.get(licenseInfo.fztime), tempfetch);
						}
						list.add(dto);
					}
				}
			} else {
				if (searchDto.getWrwType().equals(WPType.WATER)) {
					getWaterWrwInfo(searchDto, dto, dataId, t.get(licenseInfo.fztime), tempfetch);
				}
				if (searchDto.getWrwType().equals(WPType.GAS)) {
					getAirWrwInfo(searchDto, dto, dataId, t.get(licenseInfo.fztime), tempfetch);
				}
				list.add(dto);
			}
		}

		return PagingPlugin.getLocalPagingInfo(list, searchDto);
	}

	private void getWaterWrwInfo(SearchDto s, LicenseInfoDto dto, String dataId, String fzTime, List<Tuple> fetch) {
		List<Tuple> fetchtemp = new ArrayList<Tuple>();
		fetch.forEach(t -> {
			if (dataId.equals(t.get(drainInfoWaterApplyCountTwo.dataid))) {
				fetchtemp.add(t);
			}
		});
		Integer searchYear = Integer.parseInt(s.getYear());
		Integer fzYear = Integer.parseInt(fzTime.substring(0, 4));
		Integer fzMonth = Integer.parseInt(fzTime.substring(5, 7));
		Integer fzDay = Integer.parseInt(fzTime.substring(8, 10));
		DecimalFormat decimalFormat = new DecimalFormat();
		decimalFormat.applyPattern("0.000000");
		if (fzDay > 15) {
			if (fzMonth < 12) {
				fzMonth++;
			}
		}
		if (null != fetchtemp && fetchtemp.size() > 0) {
			for (Tuple m : fetchtemp) {
				double sqoneyear = 0.0;
				double sqtwoyear = 0.0;
				double sqthreeyear = 0.0;
				double sqfouryear = 0.0;
				double sqfiveyear = 0.0;
				Double total = 0.0;
				if (null != m.get(drainInfoWaterApplyCountTwo.sqoneyear)
						&& !m.get(drainInfoWaterApplyCountTwo.sqoneyear).equals("/")
						&& !m.get(drainInfoWaterApplyCountTwo.sqoneyear).equals("")) {
					sqoneyear = Double.valueOf(m.get(drainInfoWaterApplyCountTwo.sqoneyear));
				}
				if (null != m.get(drainInfoWaterApplyCountTwo.sqtwoyear)
						&& !m.get(drainInfoWaterApplyCountTwo.sqtwoyear).equals("/")
						&& !m.get(drainInfoWaterApplyCountTwo.sqtwoyear).equals("")) {
					sqtwoyear = Double.valueOf(m.get(drainInfoWaterApplyCountTwo.sqtwoyear));
				}
				if (null != m.get(drainInfoWaterApplyCountTwo.sqthreeyear)
						&& !m.get(drainInfoWaterApplyCountTwo.sqthreeyear).equals("/")
						&& !m.get(drainInfoWaterApplyCountTwo.sqthreeyear).equals("")) {
					sqthreeyear = Double.valueOf(m.get(drainInfoWaterApplyCountTwo.sqthreeyear));
				}
				if (null != m.get(drainInfoWaterApplyCountTwo.sqfouryear)
						&& !m.get(drainInfoWaterApplyCountTwo.sqfouryear).equals("/")
						&& !m.get(drainInfoWaterApplyCountTwo.sqfouryear).equals("")) {
					sqfouryear = Double.valueOf(m.get(drainInfoWaterApplyCountTwo.sqfouryear));
				}
				if (null != m.get(drainInfoWaterApplyCountTwo.sqfiveyear)
						&& !m.get(drainInfoWaterApplyCountTwo.sqfiveyear).equals("/")
						&& !m.get(drainInfoWaterApplyCountTwo.sqfiveyear).equals("")) {
					sqfiveyear = Double.valueOf(m.get(drainInfoWaterApplyCountTwo.sqfiveyear));
				}
				switch (searchYear - fzYear) {
				case 0:
					total = sqoneyear * (12 - fzMonth) / 12;
					break;
				case 1:
					total = sqtwoyear * (12 - fzMonth) / 12 + sqoneyear * fzMonth / 12;
					break;
				case 2:
					total = sqthreeyear * (12 - fzMonth) / 12 + sqtwoyear * fzMonth / 12;
					break;
				case 3:
					total = sqfouryear * (12 - fzMonth) / 12 + sqthreeyear * fzMonth / 12;
					break;
				case 4:
					total = sqfiveyear * (12 - fzMonth) / 12 + sqfouryear * fzMonth / 12;
					break;
				default:
					break;
				}
				if (m.get(drainInfoWaterApplyCountTwo.waterwrwcode).equals(PollutantEnum.CODCR.getCode())) {
					if (total != 0.0) {
						dto.setCodcr(decimalFormat.format(total));
					} else {
						dto.setCodcr("/");
					}
				}
				if (m.get(drainInfoWaterApplyCountTwo.waterwrwcode).equals(PollutantEnum.AD.getCode())) {
					if (total != 0.0) {
						dto.setAd(decimalFormat.format(total));
					} else {
						dto.setAd("/");
					}
				}

			}
		}
	}

	private void getAirWrwInfo(SearchDto s, LicenseInfoDto dto, String dataId, String fzTime, List<Tuple> fetch) {
		List<Tuple> fetchtemp = new ArrayList<Tuple>();
		fetch.forEach(t -> {
			if (dataId.equals(t.get(qAirQcPollution.dataid))) {
				fetchtemp.add(t);
			}
		});
		Integer searchYear = Integer.parseInt(s.getYear());
		Integer fzYear = Integer.parseInt(fzTime.substring(0, 4));
		Integer fzMonth = Integer.parseInt(fzTime.substring(5, 7));
		Integer fzDay = Integer.parseInt(fzTime.substring(8, 10));
		DecimalFormat decimalFormat = new DecimalFormat();
		decimalFormat.applyPattern("0.000000");
		if (fzDay > 15) {
			if (fzMonth < 12) {
				fzMonth++;
			}
		}
		if (null != fetchtemp && fetchtemp.size() > 0) {
			for (Tuple m : fetchtemp) {
				double qconeyear = 0.0;
				double qctwoyear = 0.0;
				double qcthreeyear = 0.0;
				double qcfouryear = 0.0;
				double qcfiveyear = 0.0;
				Double total = 0.0;
				if (null != m.get(qAirQcPollution.qconeyear) && !m.get(qAirQcPollution.qconeyear).equals("/")
						&& !m.get(qAirQcPollution.qconeyear).equals("")) {
					qconeyear = Double.valueOf(m.get(qAirQcPollution.qconeyear));
				}
				if (null != m.get(qAirQcPollution.qctwoyear) && !m.get(qAirQcPollution.qctwoyear).equals("/")
						&& !m.get(qAirQcPollution.qctwoyear).equals("")) {
					qctwoyear = Double.valueOf(m.get(qAirQcPollution.qctwoyear));
				}
				if (null != m.get(qAirQcPollution.qcthreeyear) && !m.get(qAirQcPollution.qcthreeyear).equals("/")
						&& !m.get(qAirQcPollution.qcthreeyear).equals("")) {
					qcthreeyear = Double.valueOf(m.get(qAirQcPollution.qcthreeyear));
				}
				if (null != m.get(qAirQcPollution.qcfouryear) && !m.get(qAirQcPollution.qcfouryear).equals("/")
						&& !m.get(qAirQcPollution.qcfouryear).equals("")) {
					qcfouryear = Double.valueOf(m.get(qAirQcPollution.qcfouryear));
				}
				if (null != m.get(qAirQcPollution.qcfiveyear) && !m.get(qAirQcPollution.qcfiveyear).equals("/")
						&& !m.get(qAirQcPollution.qcfiveyear).equals("")) {
					qcfiveyear = Double.valueOf(m.get(qAirQcPollution.qcfiveyear));
				}
				switch (searchYear - fzYear) {
				case 0:
					total = qconeyear * (12 - fzMonth) / 12;
					break;
				case 1:
					total = qctwoyear * (12 - fzMonth) / 12 + qconeyear * fzMonth / 12;
					break;
				case 2:
					total = qcthreeyear * (12 - fzMonth) / 12 + qctwoyear * fzMonth / 12;
					break;
				case 3:
					total = qcfouryear * (12 - fzMonth) / 12 + qcthreeyear * fzMonth / 12;
					break;
				case 4:
					total = qcfiveyear * (12 - fzMonth) / 12 + qcfouryear * fzMonth / 12;
					break;
				default:
					break;
				}
				if (m.get(qAirQcPollution.wrwid).equals(PollutantEnum.SO2.getCode())) {
					if (total != 0.0) {
						dto.setSo2(decimalFormat.format(total));
					} else {
						dto.setSo2("/");
					}
				}
				if (m.get(qAirQcPollution.wrwid).equals(PollutantEnum.PM.getCode())) {
					if (total != 0.0) {
						dto.setPm(decimalFormat.format(total));
					} else {
						dto.setPm("/");
					}
				}
				if (m.get(qAirQcPollution.wrwid).equals(PollutantEnum.NOX.getCode())) {
					if (total != 0.0) {
						dto.setNox(decimalFormat.format(total));
					} else {
						dto.setNox("/");
					}
				}
			}
		}

	}

	private void bulidFilterBox(SearchDto s, JPAQuery<Tuple> query) {
		if (null != s.getCodeRegionList() && s.getCodeRegionList().size() > 0) {
			query.where(baseInfo.code_region.in(s.getCodeRegionList()));
		}
		if (StringUtils.isNotBlank(s.getCodeRegion())) {
			query.where(baseInfo.code_region.eq(s.getCodeRegion()));
		}
		// 发证 列表的年用于筛选发证年限 污染物筛选框的年用于设置污染物的第一年 或第二年取值
		if (StringUtils.isNotBlank(s.getYear()) && null == s.getWrwType()) {
			query.where(licenseInfo.fztime.substring(0, licenseInfo.fztime.indexOf("-")).eq(s.getYear()));
		}
		if (StringUtils.isNotBlank(s.getDevcompany())) {
			query.where(pwBaseInfo.devcompany.contains(s.getDevcompany())
					.or(licenseInfo.xkzNum.contains(s.getDevcompany())));
		}

		if (StringUtils.isNotBlank(s.getHyid())) {
			List<CategoryDto> childs = categoryService.findByCodeChilds(s.getHyid());
			List<String> hyids = new ArrayList<String>(128);
			if (childs != null && !childs.isEmpty()) {
				childs.forEach(t -> {
					getAllHyid(t.getChilds(), t, hyids);
				});
				query.where(pwBaseInfo.hyid.in(hyids));
			}
		}
		if (null != s.getHyids() && s.getHyids().length > 0) {
			query.where(pwBaseInfo.hyid.in(s.getHyids()));
		}
		if (StringUtils.isNotBlank(s.getDate())) {
			query.where(licenseInfo.fztime.eq(s.getDate()));
		}
	}

	@Override
	public PwxkzBasicDto getBasic(String dataId) {
		PwxkzBasicDto pwxkzBasicDto = new PwxkzBasicDto();
		AuditCertDto auditCertDto = auditCertService.getOne(dataId);
		AuditBaseInfo auditBaseInfo = auditBaseInfoService.getByDataId(dataId).get(0);
		AuditBaseInfoDto auditBaseInfoDto = new AuditBaseInfoDto();
		BeanUtils.copyProperties(auditBaseInfo, auditBaseInfoDto);
		BaseInfoDto baseInfoDto = baseInfoService.getByDataId(dataId);
		pwxkzBasicDto.setAuditBaseInfoDto(auditBaseInfoDto);
		pwxkzBasicDto.setAuditCertDto(auditCertDto);
		pwxkzBasicDto.setBaseInfoDto(baseInfoDto);
		return pwxkzBasicDto;
	}

	@Override
	public LicenseInfo getOne(String dataId) {
		return licenseInfoRepository.findByDataid(dataId);
	}

	private List<String> getAllHyid(List<CategoryDto> childs, CategoryDto parent, List<String> result) {
		if (null != childs && !childs.isEmpty()) {
			childs.forEach(t -> {
				getAllHyid(t.getChilds(), t, result);
			});
		}
		if (null != parent) {
			result.add(parent.getCode());
		}
		return result;
	}

}